#pragma once

#include <iostream>
#include <string>
#include <cstring>
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <memory>
#include"inetAdder.hpp"
#include <unistd.h>
#include "common.hpp"
//#include "log.hpp"
#include<sys/wait.h>
#include <signal.h>
#include <pthread.h>
const int defaultfd = -1;
static const int backlog  =8;
class tcpserver:public Nocopy//服务器时禁止拷贝的
{
    public:
    tcpserver(uint16_t port,int sockfd = defaultfd):
    _port(port),
   _listensockfd(sockfd),
    _isrunning(false)
    {}
    void init()
    {
        //signal(SIGCHLD,SIG_IGN);//忽略SIG_CHLD信号
        //创建套接字
        _listensockfd = socket(AF_INET,SOCK_STREAM,0);
        if(_listensockfd<0)
        {
            //套接字创建失败，输出一段日志信息
            std::cout<<"socket create failed"<<std::endl;
           //exit(SOCKET_ERR);
        }

        //服务器其要绑定众所周知的端口号
        inetaddr  local(_port);
        int n = bind(_listensockfd,local.Netaddrptr(),local.Netaddrlen());
        if(n<0)
        {
            //绑定失败，应该输出一条日志信息
            std::cout<<"bind error"<<std::endl;
            //exit(BIND_ERR);
        }
        //走到这里绑定成功
        //下一步是监听，要随时监听是否有人要来连接我们
        n = listen(_listensockfd,backlog);
        if(n<0)
        {
            std::cout<<"listen error"<<std::endl;
        }
        //走到这里，监听成功
        //当夫妻处于监听状态的时候，那么他就可以被连接了
        //TCP全双工
    }
    class ThreadData
    {
        public:
        int sockfd;
        inetaddr addr;
        tcpserver* tsvr;
    };

    void Service(int sockfd,inetaddr &peer)
    {
        char buffer[1024];
        while(true)
        {
            //先读取数据
            ssize_t n = read(sockfd,buffer,sizeof(buffer)-1);
            if(n>0)
            {
                //读取成功
                buffer[n] = 0;//设置为c风格的字符串
                std::cout<<peer.Stringaddr()<<" say:"<<buffer<<std::endl;
                std::string serversay = "echo say:";
                serversay+=buffer;
                write(sockfd,serversay.c_str(),serversay.size());
            }
            else if(n == 0)
            {
                //客户端退出了
                std::cout<<"client quit"<<std::endl;
                close(sockfd);
                break;
            }
             else if(n < 0)
            {
                //客户端退出了
                std::cout<<"client quit"<<std::endl;
                close(sockfd);
                break;
            }
            //在处理数据

        }
    }
    static void* routine(void *args)
    {
        pthread_detach(pthread_self());
        ThreadData *td = static_cast<ThreadData*>(args);
        td->tsvr->Service(td->sockfd,td->addr);
        delete td;
        return nullptr;
    }
    void start()
    {
        _isrunning = true;
        while(_isrunning)
        {
            //服务器要先获取链接，然后才可以进行通信操作
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            int sockfd = accept(_listensockfd,(struct sockaddr*)&peer,&len);
            if(sockfd<0)
            {
                //获取下一个链接，不属于错误，可以给个警告日志
                continue;
            }
             //获取链接成功
             inetaddr client(peer);
             std::cout<<"accept success:peer.addr:"<<client.Stringaddr()<<std::endl;
             //这个是单进程版本，虾米那来写多进程版本
             //Service(sockfd,client);//开始进行服务
             //version 1--，下面写的是多进程版本
            //  pid_t id = fork();
            //  if(id<0)
            //  {
            //     //LOG(loglevel::FATAL)<<"fork error";//创建新的进程失败
            //  }
            //  else if(id==0)
            //  {
            //     //此时说明是子进程
            //     //子进程能看到父进程的sockfd
            //     //也能看到父进程的listen套接字
            //     //但是我们不想让子进程看到
            //     close(_listensockfd);
            //     if(fork()>0)//再次fork
            //     {
            //         exit(0);
            //     }
            //     Service(sockfd,client);//孙子进程来处理，处理完成孤儿，系统来回收孙子进程
            //     exit(0);
            //  }
            //  else{
            //     //返回值大于零，这个是父进程
            //     close(sockfd);
            //     //父进程要等待子进程
            //     pid_t rid =waitpid(id,nullptr,0);
            //     //(void*)rid;

            //  }
            //多线程版本 version2
            //用原生线程
            ThreadData *td = new ThreadData();
            td->addr = client;
            td->sockfd = sockfd;
            td->tsvr = this;
            pthread_t tid;
            pthread_create(&tid,nullptr,routine,td);
        }
       

        _isrunning = false;
    }
    ~tcpserver()
    {}
    private:
    uint16_t _port;
    int _listensockfd;
    bool _isrunning;
};